#pragma 

#include "comm/types.h"

//页表与页数量
#define PAGE_NUM  1024  

#define PTE_P      (1<<0)   //映射关系存在
#define PDE_P      (1<<0)   //映射关系存在


#define PDE_W      (1<<1)   //可读写
#define PTE_W      (1<<1)   //可读写

#define PTE_U      (1<<2)   //用户可访问
#define PDE_U      (1<<2)   //用户可访问


 


typedef union _pde_t {
    uint32_t v;
    struct {
        uint32_t present : 1;                   // 0 (P) 存在；必须设置为1才能映射4KB的页面
        uint32_t write_disable : 1;             // 1 (R/W) 读/写，如果为0，可能不允许写入
        uint32_t user_mode_acc : 1;             // 2 (U/S) 如果为0，不允许用户模式访问
        uint32_t write_through : 1;             // 3 (PWT) 页面级别写入直通
        uint32_t cache_disable : 1;             // 4 (PCD) 页面级别缓存禁用
        uint32_t accessed : 1;                  // 5 (A) 已访问
        uint32_t : 1;                           // 6 忽略；
        uint32_t ps : 1;                        // 7 (PS) 页面大小，设置为1时表示4MB页面
        uint32_t : 4;                           // 11:8 忽略
        uint32_t phy_pt_addr : 20;              // 高20位页表物理地址
    };
} pde_t;



typedef union _pte_t {
    uint32_t v;
    struct {
        uint32_t present : 1;                   // 0 (P) 存在标志；必须为1以映射4KB的页面
        uint32_t write_disable : 1;             // 1 (R/W) 读/写属性；如果为0，可能不允许写入
        uint32_t user_mode_acc : 1;             // 2 (U/S) 用户/超级用户模式访问控制；如果为0，不允许用户模式访问
        uint32_t write_through : 1;             // 3 (PWT) 页面级别写入直通；如果为1，页面写入直接反映到物理内存
        uint32_t cache_disable : 1;             // 4 (PCD) 页面级别缓存禁用；如果为1，页面对CPU缓存不可见
        uint32_t accessed : 1;                  // 5 (A) 已访问标志；如果页面被访问过，则设置为1
        uint32_t dirty : 1;                     // 6 (D) 脏标志；如果页面被写入过，则设置为1
        uint32_t pat : 1;                       // 7 PAT 页面属性表；用于定义页面的缓存属性
        uint32_t global : 1;                    // 8 (G) 全局页面；如果为1，TLB中的页面对所有地址空间可见
        uint32_t : 3;                           // 忽略
        uint32_t phy_page_addr : 20;            // 高20位物理地址；页表项指向的物理页面地址的高20位
    };
} pte_t;



static inline void mmu_set_page_dir(uint32_t paddr)
{
    write_cr3(paddr);
}


//虚拟地址在一级页表的索引
static inline  uint32_t pde_index(uint32_t vaddr)
{
    //高10位作为索引
    int index = (vaddr >> 22);
    return index;
}
//虚拟地址在二级页表的索引
static inline  uint32_t pte_index(uint32_t vaddr)
{
    return ((vaddr >> 12) & 0x3FF);
}

//页表地址
static inline uint32_t pde_paddr(pde_t* pde)
{
    return (pde->phy_pt_addr << 12);
}

//
static inline uint32_t pte_paddr(pte_t* pte)
{
    return (pte->phy_page_addr << 12);
}


static inline uint32_t  get_pte_perm (pte_t * pte) 
{
    return (pte->v & 0x1FF);                   
}